/*
 * File         : ipport_com.c
 * This file is part of HZ-RTOS
 * COPYRIGHT (C) 2015 - 2016, HZIT Team
 * 
 * Change Logs:
 * DATA             Author          Note
 * 2015-12-17       D.H.            create the first version
 */

#include "ipport_com.h"
#include "ippkg.h"

#include "unistd.h"
#include "errno.h"
   
#include "shell.h"

#include "lwip/tcp.h"
   
#if 0

#define IPPORT_COM_DEVICE_NAME     "ipcom"
#define IPPORT_COM_TCP_PORT        2300
   
static struct ipport_com ipport_com;

static err_t ipport_com_open ( struct hz_device *device )
{
    return 0;
}

static ssize_t ipport_com_aio_read ( struct hz_device *device, char __user *buffer, size_t size, loff_t loff )
{
    size_t len = size;
    os_u32 data;
    char __user *recv_buffer = buffer;
    struct ipport_com *ipport_com = (struct ipport_com *)device->priv;
    
    while (len--)
    {
        if (hz_mailbox_recv(&ipport_com->mailbox, &data, HZ_MAILBOX_RECV_WAIT) == HZ_EOK)
        {
            *recv_buffer++ = (char)data;
        }
    }
  
    return (ssize_t)(recv_buffer - buffer);
}

static ssize_t ipport_com_aio_write ( struct hz_device *device, const char __user *buffer, size_t size, loff_t loff )
{
    struct ipport_com *ipport_com = (struct ipport_com *)device->priv;
    struct tcp_pcb *pcb = (struct tcp_pcb *)ipport_com->arg;
  
    tcp_write(pcb, buffer, size, 1);
    tcp_output(pcb);
  
    return size;
}

static ssize_t ipport_com_read ( struct hz_device *device, char __user *buffer, size_t size, loff_t loff )
{
    size_t len = size;
    os_u32 data;
    char __user *recv_buffer = buffer;
    struct ipport_com *ipport_com = (struct ipport_com *)device->priv;
    
    while (len--)
    {
        if (hz_mailbox_recv(&ipport_com->mailbox, &data, HZ_MAILBOX_RECV_WAIT) == HZ_EOK)
        {
            *recv_buffer++ = (char)data;
        }
    }
  
    return (ssize_t)(recv_buffer - buffer);
}

static ssize_t ipport_com_write ( struct hz_device *device, const char __user *buffer, size_t size, loff_t loff )
{   
    struct ipport_com *ipport_com = (struct ipport_com *)device->priv;
    struct tcp_pcb *pcb = (struct tcp_pcb *)ipport_com->arg;
  
    tcp_write(pcb, buffer, size, 1);
    tcp_output(pcb);
    
    return size;
}

static err_t ipport_com_dev_configuration(void)
{
    struct hz_device *device;
    err_t err;
    
    if ((device = device_create(1)) == HZ_NULL)
    {
        return -1;
    }
    
    device->open      = ipport_com_open;
    device->read      = ipport_com_read;
    device->write     = ipport_com_write;
    device->aio_read  = ipport_com_aio_read;
    device->aio_write = ipport_com_aio_write;
    
    device->priv      = &ipport_com;
    
    device_register(device, IPPORT_COM_DEVICE_NAME);
    
    shell_dev_create(IPPORT_COM_DEVICE_NAME, &err, SHELL_DEVICE_NO_ACK);
    
    ipport_com.shell_dev = shell_dev_find(IPPORT_COM_DEVICE_NAME);
    
    return 0;
}

static void ipport_com_connect_err( void *arg, err_t err )
{
    ipport_com.arg = HZ_NULL;
}

static err_t ipport_com_recv_data( void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err )
{
    if ( HZ_NULL != p )
    {      
        os_u32 bytes_recv;
        os_u32 i = 0;
        os_u8 buffer_recv[6];
        struct ipport_com *ipport_com = (struct ipport_com *)arg;
        hz_mailbox_t *mailbox = &ipport_com->mailbox; 
      
        tcp_recved( pcb, p->tot_len );
        
        bytes_recv = ippkg_unpack(p, buffer_recv, 6);    
        
        while( bytes_recv-- )
        {
            hz_mailbox_send(mailbox, buffer_recv[i++] );
        }
        
        pbuf_free(p);
    }
  
  
    return 0;
}

static err_t ipport_com_accept( void *arg, struct tcp_pcb *pcb, err_t err )
{
    const char *log = "Welcom to use HZIT Embedded Telnet Com.\r\n";
    
    ipport_com.arg = pcb;
  
    tcp_err(  pcb, ipport_com_connect_err);
    tcp_recv( pcb, ipport_com_recv_data);
    
    tcp_write(pcb, log, hz_strlen(log), 1); 
    
    return 0;
}

err_t ipport_com_configuration(void)
{
    struct tcp_pcb *pcb;
    
    HZ_ASSERT_KERNEL( ipport_com_dev_configuration() == HZ_EOK );
    
    HZ_ASSERT_KERNEL( (pcb = tcp_new()) != HZ_NULL );
    tcp_bind( pcb, IP_ADDR_ANY, IPPORT_COM_TCP_PORT ); 
    pcb = tcp_listen(pcb);
    tcp_accept( pcb, ipport_com_accept );
    tcp_arg(pcb, &ipport_com);
    
    hz_mailbox_init(&ipport_com.mailbox);
    
    return 0;
}

#endif

